#include <iostream.h>
#include "string2.h"
#include "fileread.h"

/*--------------------------------------------------------------------------*/
/*  FILEREADER.C							    */
/*    This class allows the user to read and write to an external file	    */
/*									    */
/*- Modfication History ----------------------------------------------------*/
/*  When:	Who:			Comments:			    */
/*									    */
/*  21-Sep-93	Christopher G. Healey	Initial implementation		    */
/*--------------------------------------------------------------------------*/


void filereader::close()

   //  This method closes either the input or output stream
{
   switch( mode ) {			// Select file stream to close
   case READ:				// Close input stream
      if ( inp_fp != &cin ) {		// Ensure we don't try to close cin
         ((ifstream *) inp_fp)->close();
      }

      mode = UNDEF;			// Reset mode to undefined
      break;

   case APPEND:				// Close output stream
   case WRITE:
      if ( out_fp != &cout ) {		// Ensure we don't try to close cout
         ((ofstream *) out_fp)->flush();
         ((ofstream *) out_fp)->close();
      }

      mode = UNDEF;			// Reset mode to undefined
      break;

   default:
      break;
   }
}					// End method close


int filereader::eof()

   //  This method reports true if EOF detected, FALSE otherwise
{
   switch( mode ) {			// Select file stream to query
   case READ:				// Query input stream
      return inp_fp->eof();

   case APPEND:				// Query output stream
   case WRITE:
      return out_fp->eof();

   default:
      return 0;
   }
}					// End eof method


int filereader::getline( string& line )

   //  This method reads the next line from the input stream, and returns
   //  it to the user as a string
   //
   //  line:  Storage for current line
{
   char  buf[ 10240 ];			// Buffer to hold next line


   if ( mode != READ ) {		// Ensure read mode active
      return 0;
   }

   buf[ 0 ] = '\0';			// Read line from input stream
   inp_fp->getline( buf, 10240 );

   //  If no line present and EOF reached, return FALSE to caller

   if ( buf[ 0 ] == '\0' && inp_fp->eof() ) {
      return 0;
   }

   line = buf;				// Copy buffer to string
   return 1;
}					// End method getline


int filereader::open( char m )

   //  This method opens either cin or cout for direct stream access
   //
   //  m:  Mode to open (r=read from cin, w=write to cout)
{
   int  rc = 1;				// Return code


   switch( m ) {
      case 'r':
      case 'R':
         inp_fp = &cin;
         mode = READ;
         break;

      case 'w':
      case 'W':
         out_fp = &cout;
         mode = WRITE;
         break;

      default:
         cout << "Error: Unknown mode " << mode << " specified\n";
         rc = 0;
         mode = UNDEF;
         break;
   }					// End switch on mode

   return rc;
}					// End method open


int filereader::open( string fname, char m )

   //  This method opens the given file in the given mode (r or w)
   //
   //  fname:  Name of file to open
   //  m:      Mode to open (r=read, w=write)
{
   int  rc = 1;				// Return code


   switch( m ) {
      case 'r':				// Open for read
      case 'R':
         close();			// Close any currently open stream

         inp_fp = new ifstream;
         ((ifstream *) inp_fp)->open( fname, ios::in );

         if ( !inp_fp->good() ) {
            cout << "Error: Input file " << fname << " does not exist\n";
            rc = 0;

         } else {
            mode = READ;
         }

         break;

      case 'w':				// Open for write
      case 'W':
         close();			// Close any currently open stream

         out_fp = new ofstream;
         ((ofstream *) out_fp)->open( fname, ios::out );

         if ( !out_fp->good() ) {
            cout << "Error: Output file " << fname << " would not open\n";
            rc = 0;

         } else {
            mode = WRITE;
         }

         break;

      case 'a':				// Open for append
      case 'A':
         close();			// Close any currently open stream

         out_fp = new ofstream;
         ((ofstream *) out_fp)->open( fname, ios::app );

         if ( !out_fp->good() ) {
            cout << "Error: Output file " << fname << " would not open\n";
            rc = 0;

         } else {
            mode = APPEND;
         }

         break;

      default:
         cout << "Error: Unknown mode " << mode << " specified\n";

         rc = 0;
         mode = UNDEF;

         break;
   }					// End switch on mode

   return rc;
}					// End method open


int filereader::next( string buf[], int size, char sep )

   //  This method reads a single line, parses it into individual words,
   //  and stores those words in the given array
   //
   //  buf:   Buffer to use to store words
   //  size:  Maximum size of buffer
   //  sep:   Separator character to use
{
   int   elem = 0;			// Current buffer element
   int   i = 0;				// Current line element
   char  line[ 1024 ];			// Current input line


   if ( mode != READ ) {		// Ensure read mode active
      return 0;
   }

   do {					// Continue until tokens or EOF
      line[ 0 ] = '\0';			// Read next line
      inp_fp->getline( line, 1024 );

      elem = parse( buf, size, line, sep );
   }
   while( elem == 0 && !inp_fp->eof() );

   return elem;
}					// End method next


int filereader::parse( string buf[], int size, string line, char sep )

   //  This method parses a single line into individual words, and stores
   //  those words in the given array
   //
   //  buf:   Buffer to use to store words
   //  size:  Maximum size of buffer
   //  line:  Line to parse
   //  sep:   Separator character to use
{
   int   elem = 0;			// Current buffer element
   int   i = 0;				// Current line element


   while( i != line.len() && elem < size ) {

   //  First, set current token string to be empty, then strip any white
   //  space which may be sitting in front of the next token

      buf[ elem ] = "";
      for( ; i != line.len() && line[ i ] == sep; i++ );

      if ( i == line.len() )		// Line ended in sep chars?
         return elem;

      if ( line[ i ] == '\"' ) {	// Process quoted text?
         i++;				// Ignore quote character

         while( i != line.len() && line[ i ] != '\"' )
            buf[ elem ] = buf[ elem ] + line[ i++ ];

         if ( i == line.len() ) {
            cout << "Warning: Mismatched quotes\n";
            return elem;
         }

         i++;				// Ignore closing quote
         elem++;			// Increment token count

   //  Otherwise, if not end of line, process normal token

      } else {
         while( i != line.len() && line[ i ] != sep )
            buf[ elem ] = buf[ elem ] + line[ i++ ];

         elem++;			// Increment token count
      }
   }

   return elem;				// Return token count
}					// End method next


void filereader::write( string line )

   //  This method writes a single line to the output stream
   //
   //  line:  Line to send to output stream
{
   if ( mode != APPEND && mode != WRITE ) {
      return;
   }

   *out_fp << line;
}					// End method write


filereader::filereader()

   //  Constructor for filereader objects, set mode to undefined
{
   mode = UNDEF;
}					// End constructor method


filereader::~filereader()

   //  Destructor for filereader objects, ensure file is closed properly
{
   close();
}					// End destructor method
